/**
 * =================================================
 *
 * A wangXi javascript daily dev toolkit since 2014
 *
 * @author wangXi <iwisunny@gmail.com>
 *
 * @copyright MIT
 *
 * use AMD js spec
 * =================================================
 */
(function(g){
    var w = g.wxi || {};

    //basic prop/function from native js
    var toStr = Object.prototype.toString,
        hasOwn = Object.prototype.hasOwnProperty,
        slice = Array.prototype.slice,
        push = Array.prototype.push,
        indexOf = Array.prototype.indexOf,
        trim = String.prototype.trim,

        doc = g.document,
        loc = g.location,
        nav = g.navigator,

        isFunction = function(obj){
            return toStr.call(obj) === "[object Function]";
        },
        isArray = function(obj){
            return toStr.call(obj) === "[object Array]";
        },
        isObject = function(obj){
            return toStr.call(obj) === "[object Object]";
        };

    //child obj extends properties of parent obj
    var extend = function(child,parent){
        (child !== null) && isObject(child) && (function(){
            for(var prop in parent){
                if(hasOwn.call(parent, prop)){
                    child[prop] = parent[prop];
                }
            }
        })();
        return child;
    };

    /**
     * 采用Js原型链模拟传统的OOP
     *
     */
    var _class = function(parent, mixin){
        //temporary constructor to be returned
        var base = function(){
                //follow php __construct, assume js constructor named __construct
                this.__construct.apply(this, arguments);
            },

        //proxy constructor
            F = function(){};

        //override prototype chain
        base.fn = base.prototype;
        //add blank callback to __construct
        base.fn.__construct = function(){};

        if(parent && isFunction(parent) ){
            F.prototype = parent.prototype;
            base.fn = new F();
        }
        else if(parent && isObject(parent) ){
            extend(base.fn, parent);
        }

        if(mixin && isObject(mixin) ){
            extend(base.fn, mixin);
        }

        return base;
    };

    /**
     * 构造命名空间，便于分离设计，模块化开发
     *
     * @param ns
     * @param map
     * @param with_this
     * @returns {wxi|*|{}}
     */
    var namespace = function(ns, map){
        var parts = ns.split('.'),
            parent = g;

        //parts = parts[0] == 'wxi' ? parts.slice(1) : parts;

        for(var i= 0, len = parts.length; i<len; i++){
            if(parent[parts[i]] === undefined){
                parent[parts[i]] = {};
            }
            parent = parent[parts[i]];
        }

        if(isObject(map)){
            //add extra properties to current namespace
            extend(parent, map);
        }

        /*
         //bind to global
         parts.unshift('g');
         eval(parts.join('.')+' = parent');
         */

        return parent;
    };

    //fix IE problems
    if(!trim){
        String.prototype.trim = function(){
            return this.replace(/^(\s*)(.+)(\s*)/i, '$2');
        };
    }
    if(!indexOf){
        Array.prototype.indexOf = function(needle){
            for(var i= 0, len = this.length; i< len; i++){
                if(needle == this[i]){
                    return i;
                }
                else{
                    continue;
                }
            }
            return -1;
        };
    }

    var for_each = function(arr, fx){
        if(isObject(arr)){
            fx.call(null, arr);
        }
        else if(isArray(arr)){
            for(var i= 0, len = arr.length; i<len; i++){
                fx.call(null, arr[i], i);
            }
        }

    };

    var in_array = function(needle, stack){
        if(!isArray(stack)) return false;

        return stack.indexOf(needle) !== -1;
    };

    //require js config
    var require_conf = {
        jsBaseUrl: '/public/js/',
        cssBaseUrl: '/public/css/',
        path: []
    };

    w.requireConfig=require_conf;

    var set_require_conf = function(option){
        extend(w.requireConfig, option);
        return w;
    };

    //loaded js file, registry pattern
    w.loaded=[];

    var is_loaded=function(file){
        if(file!==undefined){
            return in_array(file, w.loaded);
        }
        return w.loaded;
    };

    //单个文件的异步加载
    var require = function(url, callback, option){
        var args = arguments;

        if(isArray(args[0])){
            //多文件同步加载模式
            use.apply(this, args);
        }
        else{
            //单文件异步加载模式
            var url_suffix = url.match(/\.(\w+)$/),
                type = url_suffix && url_suffix[1],
                accept_file = ['js', 'css'],
                s,
                fpath,
                path_prefix = '';

            if(!in_array(type, accept_file)){
                throw new Error('unknown file type, only accept js, css');
            }

            option = option || w.requireConfig;

            if(type == 'js'){
                s = doc.createElement('script');
                s.type = 'text/javascript';
                path_prefix = option.jsBaseUrl;
            }
            else if(type == 'css'){
                s = doc.createElement('link');
                s.rel = 'stylesheet';
                s.type = 'text/css';
                path_prefix = option.cssBaseUrl;
            }
            else{
                return false;
            }

            if(s.readyState){
                s.onreadystatechange = function(){
                    if(s.readyState == 'loaded' || s.readyState == 'complete'){
                        s.onreadystatechange = null;
                        w.loaded.push(url);
                        isFunction(callback) && callback();
                    }
                }
            }
            else{
                s.onload = function(){
                    w.loaded.push(url);
                    isFunction(callback) && callback();
                }
            }

            if( /^\.{1,2}\/.+$/.test(url) ){
                fpath = path_prefix + /^\.{1,2}\/(.+)$/.exec(url)[1];
            }
            else if( /^(https?:\/\/)/.test(url) || /^\//.test(url) ){
                fpath = url;
            }
            else{
                fpath = path_prefix + url;
            }

            if( !RegExp( '\\.' + type + '$').test(fpath) ){
                fpath += '.' + type;
            }

            if(type == 'js'){
                s.src = fpath;
            }
            else{
                s.href = fpath;
            }

            doc.getElementsByTagName('head')[0].appendChild(s);
        }

    };

    //多文件按依赖顺序加载，用异步回调触发下一次加载，模拟同步阻塞
    var use = function(file_arr, callback, option){
        var cur_file = file_arr.shift();
        if(file_arr.length > 0){
            //递归使用 require 异步加载
            require(cur_file, function(){
                use(file_arr,callback,option);
            },option);
        }
        else{
            require(cur_file, function(){
                isFunction(callback) && callback();
            }, option);
        }
    };

    var wait=function(js_file, callback){
        var timer=setInterval(function(){
            if(is_loaded(js_file)){
                clearInterval(timer);
                timer=null;
                callback.apply(arguments);
            }
        },100);

    };

    extend(w, {
        setConfig: set_require_conf,
        require: require,
        namespace: namespace,
        Class: _class,
        extend: extend,
        map: for_each,
        isFunction: isFunction,
        isObject: isObject,
        isArray: isArray,
        inArray: in_array,
        isLoaded: is_loaded,
        wait:wait
    });

    //fix global namespace error
    g.wxi=w;

    if(typeof define =='function' && define.amd){
        define('wxi',[],function(){
            return w;
        });
    }
    else{
        return w;
    }

})(this);

/**
* @namespace util
* 实用工具类
*/
wxi.namespace('wxi.util', {
    //check error images, replace with default placeholder
    checkImageError: function(option){
        option = wxi.extend({
            placeholder: '/public/img/placeholder.jpg'
        }, option);

        $('img').error(function(){
            $(this).attr('src', option.placeholder);
        });
    },
    //jquery.gritter wrapper
    tipMsg: function(title, msg, delay, cb){

        if(arguments.length==1){
            msg=title;
            title='';
        }
        if(arguments[3]==undefined && typeof arguments[2]=='function'){
            cb=arguments[2];
            delay=800;
        }

        var _run = function(){
            //$.gritter wrapper
            $.gritter.add({
                'title': title || '操作提示',
                'text': msg || '提示信息...',
                'time': delay || 1000
            });

            typeof cb=='function' && (setTimeout(function(){
                cb.apply(this, arguments);
            }, parseInt(delay)));
        };

        //pre check if $.gritter is loaded
        if($.gritter === undefined){
            //not load jq.gritter, try load it async
            var loaded = false;
            //TODO: try to use requirejs
            if(typeof require == 'function'){
                require(['jquery.gritter.min'], function (jq_tip) {
                   _run();
                });
            }
            else{
                wxi.require('jquery.gritter.min.js', function(){
                    try{
                        if($.gritter){
                            loaded = true;
                            _run();
                        }
                        else{
                            throw new Error('jq.gritter not loaded');
                        }
                    }
                    catch(e){
                        console.error(e.message);
                    }

                });
            }

        }
        else{
            _run();
        }

    },

    //area content lazy loader
    loadContent: function(area, fx, timeout){
        var icon = '/public/img/loading.gif',
            html =  '<div style="margin-left:40%;" id="loading-area">' +
                '<img src="'+ icon +  '" width="100px" height="100px"/></div>';

        if(typeof area =='string'){
            area=$(wxi.string.trim(area, ['#','.'],1));
        }
        else{
            area=$(area);
        }

        $(area).html(html);

        var remove_icon=function(){
            $(area).find('#loading-area').remove();
        };

        if( timeout === undefined){
            fx(remove_icon);
        }
        else{
            setTimeout(fx, parseInt(timeout));
        }

    },
    //util to get cookie value by name
    getCookie: function(cname){
        var cookie = document.cookie.split(";");
        if(cname === undefined) return cookie.join("\n");

        for(var i= 0, len = cookie.length; i < len; i++){
            var part = cookie[i].split('=');
            if($.trim.call(part[0]) === cname){
                return decodeURIComponent(part[1]);
            }
        }
    },
    setCookie: function(cname, cval, expire, domain, path){
        var domain = domain || 'yourdomain.com',
            path = path || '/',
        //cookie string part
            cs = cname + '=' + encodeURIComponent(cval),
            tm = new Date,
            now = +tm;

        // use expire as seconds
        if(expire > 0){
            tm.setTime(now + parseInt(expire)*1000 );
        }
        else{
            tm.setTime(now -1 );
        }
        expire = tm.toGMTString();
        cs += "; expires=" + expire;
        cs += '; domain='+domain;
        cs += '; path='+path;
        document.cookie = cs;
    },

    getCache: function(key){
        if(key===undefined){
            return wxi.util._cache|| {};
        }
        return wxi.util._cache ? wxi.util._cache[key] : undefined;
    },
    setCache: function(key, data){
        var c=wxi.util._cache || {};
        c[key]=data;

        wxi.util._cache=c;
        return data;

    },
    clearCache: function(){
        wxi.util._cache={};
        return true;
    },

    /**
     *@return 根据表单name字段生成的 entity 对象,适用于symfony的form生成
     */
    preCheckForm: function(form_wrap, strip_str){
        var form_data=form_wrap.serialize();

        return (function(){
            return wxi.string.qs2obj(form_data, function(obj){
                var ret={};
                if(wxi.isObject(obj)){
                    for(var p in obj){

                        var data=decodeURIComponent(obj[p]);
                        var filter_p=decodeURIComponent(p);

                        var filtered_key= filter_p.replace(strip_str,'');
                        filtered_key=filtered_key.substring(1, filtered_key.length-1);

                        ret[filtered_key]=data;
                    }

                    if('_token' in ret){
                        delete ret._token;
                    }
                }

                return ret;

            });

        })();

    },

    /**
     * 填充下拉框
     * @param select_obj
     * @param fill_data
     * @param with_val_id
     */
    fillSelect: function(select_obj, fill_data, with_val_id){
        var cont='<option value="0">--请选择--</option>';

        with_val_id=with_val_id || false;

        if(wxi.isArray(fill_data)){
            wxi.map(fill_data, function(row, idx){
                //iteration , row is city object
                //cont += '<option value="'+row.id+'">'+row.name+'</option>'+"\n";
                if(with_val_id){
                    cont += '<option value="'+row.id+'">'+row.name+'</option>'+"\n";
                }
                else{
                    cont += '<option value="'+row+'">'+row+'</option>'+"\n";
                }
            });
        }
        else if(wxi.isObject(fill_data)){
            for(var ct_name in fill_data){
                cont += '<option value="'+ct_name+'">'+ct_name+'</option>'+"\n";
            }
        }

        $(select_obj).html(cont);
    },

    /**
     * 加载富文本编辑器
     * @param editor_id
     * @param cb
     */
    loadEditor: function(editor_id, cb){
        var prefix='/public/plugins/ueditor/';
        var js_files=[
            'ueditor.config.js',
            'ueditor.all.min.js',
            'lang/zh-cn/zh-cn.js'
        ];

        //override ueditor path
        window.UEDITOR_HOME_URL=prefix;
        var ueditor_conf={
            toolbars: [
                [
                    'source', '|','undo', 'redo', '|','autotypeset','pasteplain', 'formatmatch','removeformat',
                    '|','justifyleft','justifyright','justifycenter','justifyjustify',
                    '|','forecolor', 'backcolor', 'bold', 'underline', 'strikethrough','horizontal', 'link','unlink',
                    'insertorderedlist', 'insertunorderedlist','rowspacingtop','rowspacingbottom',
                    '|','inserttable','deletetable',
                    '|','insertrow','insertcol','mergeright','mergedown',
                    '|','insertparagraphbeforetable',
                    '|','splittorows', 'splittocols','splittocells', 'deletecaption',
                    '|','inserttitle','mergecells','edittable','edittd',
                    '|','simpleupload', 'insertimage',
                    '|','emotion',
                    '|','searchreplace','fullscreen','imagenone','imageleft','imageright','imagecenter',
                    'lineheight','edittip '
                ]
            ],

            enterTag:'',
            //initialFrameHeight:300,
            allowDivTransToP: false,

            //服务端配置
            serverUrl: prefix + 'php/controller.php'
        };

        wxi.require(js_files,function(){

            UE.getEditor(editor_id, ueditor_conf).ready(function(){
                var ue=UE.getEditor(editor_id);

                cb.apply(null, [ue]);

                //debug info
                console.info('editor loaded');

            });


        },{jsBaseUrl:prefix} );

    },

    /**
     * 封装loadContent, loadEditor, ajax lazy load ueditor
     * @param wrap
     * @param editor_id
     * @param callback
     */
    registerEditor: function(wrap, editor_id, callback){
        //cb 为wxi.util.loadContent的闭包函数，用于回调完成之后移除loading-icon
        wxi.util.loadContent(wrap, function(cb){

            //loadEditor完成时调用cb,属于partial valuate,然后再去执行附加匿名函数
            wxi.shopBundle.loadEditor(editor_id, function(ue){
                //ue 为闭包变量
                cb.call();

                typeof callback == 'function' && callback.apply(null, [ue]);

            });
        });
    }


});

/**
* @namespace string
* 字符串处理类
*/
wxi.namespace('wxi.string', {
    //uppercase first char
    ucfirst: function(str){
        return (str[0]).toUpperCase() + str.substr(1);
    },

    //query string to json
    qs2obj: function(qs, filter){
        var obj = {};

        filter=filter || '';

        if(typeof qs == 'string'){
            var parts = qs.split('&');
            wxi.map(parts, function(item){
                var _item = item.split('=');
                obj[_item[0]] = _item[1];
            });
        }

        //post filter
        if(filter && typeof filter == 'function'){
            return filter.apply(null, [obj, ]);
        }

        return obj;
    },

    trim: function(str, blacklist, trim_type){
        //TODO：改为静态属性
        var TRIM_LEFT= 1,
            TRIM_RIGHT= 2,
            TRIM_BOTH= 3;   //去除两端

        blacklist=blacklist || '';
        trim_type=trim_type || TRIM_BOTH;

        var trim_left=function(str,blacklist){
            if(wxi.isArray(blacklist)){
                exp=new RegExp('^'+ blacklist.join('|'));
            }
            else{
                exp=new RegExp('^'+blacklist);
            }
            return str.replace(exp,'');
        };
        var trim_right=function(str, blacklist){
            if(wxi.isArray(blacklist)){
                exp=new RegExp( blacklist.join('|')+'$');
            }
            else{
                exp=new RegExp(blacklist+'$');
            }
            return str.replace(exp,'');
        };

        var exp=null;

        if(trim_type == TRIM_LEFT){
            return trim_left(str, blacklist);
        }
        else if(trim_type == TRIM_RIGHT){
            return trim_right(str, blacklist);
        }
        else if(trim_type == TRIM_BOTH){
            //assume trim both
            var s=trim_left(str,blacklist);
            return trim_right(s, blacklist);
        }

    },

    htmlEncode: function(raw_str){
        if(!raw_str) return '';
        return raw_str.replace(/&lt;/g, '<').replace(/&gt;/g,'>');
    },

    //邮箱验证
    isEmail: function(email){
        return /^([\w_]+)@([\w_]+)(\.[\w_]+){1,2}$/.test(email);
    },
    //手机号验证
    isPhone: function(phone){
        return /^1\d{10}$/.test(phone);
    }

});

/**
* @namespace: ui
* 表现层处理类
*/
wxi.namespace('wxi.ui', {
    //add modal box, based on bootstrap modal js component
    modal: function(opt){
        var opt = wxi.isObject(opt) ? opt :  {title: '', msg: '', cb:''},
            title = opt.title || 'modal title';
        var target;

        if(opt.target !== undefined){
            //target should has .wx-modal class
            target = $('.wx-modal').filter(function(i){
                return $(this).data('target') == 'md-'+opt.target;
            });
        }
        else{
            //the only modal instance
            target = $('#wx-modal');
        }

        //save target in global
        wxi.modal = target;

        var md = target,
            md_title = md.find('.modal-title'),
            md_body = md.find('.modal-body'),
            md_foot = md.find('.modal-footer');

        md_body.css('height', opt.height ? opt.height : '120px');
        md_body.parent('.modal-content').css('width', opt.width ? opt.width : '100%');
        md.css('left', opt.left ? opt.left : 0);

        md_title.text(title);

        if(opt.hide_foot===true){
            md_foot.hide();
        }
        else{
            md_foot.show();
        }

        if(opt.ok_txt){
            md_foot.children(':last').text(opt.ok_txt);
        }
        if(opt.cancel_txt){
            md_foot.children(':first').text(opt.cancel_txt);
        }

        do{
            if(opt.msg === false){
                break;
            }
            else if(typeof opt.msg == 'function'){
                md_body.html(opt.msg.call(null));
            }
            else {
                md_body.html(opt.msg);
            }
        }while(0);

        md_foot.find('.btn-primary').unbind('click');

        target.modal({
            keyboard: false,
            backdrop: false //点击遮罩不会退出
        }).show();

        if(opt.cb && typeof opt.cb =='function'){
            md_foot.find('.btn-primary').bind('click', function(){
                opt.cb( $(this), $(this).parents('#wx-modal') );
            });
        }

        //is shown event
        if(opt.is_shown && typeof opt.is_shown == 'function'){
            target.off('shown.bs.modal');
            target.on('shown.bs.modal', function(){
                opt.is_shown( target );
            });
        }
    }

});
